package com.tg.appcommon.android;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.text.TextUtils;
import android.util.Log;

import com.appbase.custom.BuildConfig;
import com.tange.base.toolkit.TGThreadPool;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;

public class SoundPlayerManager {

    private static final String TAG = "SoundPlayerManager";
    private static final String LOCAL_SOUND_CACHE_DIR = "online_sound_cache";

    private MediaPlayer mediaPlayer;

    private final Context context;

    private final Object lock = new Object();

    private boolean destroyCalled = false;

    public static SoundPlayerManager create(Context context) {
        return new SoundPlayerManager(context);
    }

    private SoundPlayerManager(Context context) {
        this.context = context;
    }

    public void download(String url, boolean playAfterDownload) {

        if (!BuildConfig.device_addSupport_sound_play_enabled) {
            return;
        }

        if (TextUtils.isEmpty(url)) {
            TGLog.i(TAG, "[download]: url empty");
            return;
        }

        if (destroyCalled) {
            TGLog.i(TAG, "[download]: destroyed , skip");
            return;
        }

        TGLog.i(TAG, "[download]: url = " + url);
        TGLog.i(TAG, "[download]: playAfterDownload = " + playAfterDownload);

        TGThreadPool.execute(() -> {
            try {
                File dir = new File(context.getFilesDir(), LOCAL_SOUND_CACHE_DIR);
                if (!dir.exists()) {
                    dir.mkdirs();
                }

                byte[] bytesOfMessage = url.getBytes("UTF-8");
                MessageDigest md = null;
                md = MessageDigest.getInstance("MD5");
                byte[] theMD5digest = md.digest(bytesOfMessage);
                String fileName = new BigInteger(1, theMD5digest).toString(16);

                File file = new File(dir, fileName);

                TGLog.i(TAG, "[download]: local cache path = " + file.getAbsolutePath());

                if (file.exists()) {
                    TGLog.i(TAG, "[download]: local cache already exist.");
                    if (playAfterDownload) {
                        TGLog.i(TAG, "[download]: play local cache");
                        playSound(file.getAbsolutePath());
                    }
                    return;
                }

                final OkHttpClient client = new OkHttpClient();
                final Request request = new Request.Builder().url(url).build();
                final Response response = client.newCall(request).execute();
                if (!response.isSuccessful()) {
                    TGLog.i(TAG, "[download]: response failed");
                    return;
                }

                TGLog.i(TAG, "[download]: response = " + response);

                final ResponseBody body = response.body();
                final long contentLength = body.contentLength();
                final BufferedSource source = body.source();
                final BufferedSink sink = Okio.buffer(Okio.sink(file));

                sink.writeAll(source);
                sink.flush();

                TGLog.i(TAG, "[download]: download finish , contentLength = " + contentLength);

                if (!playAfterDownload) {
                    TGLog.i(TAG, "[download]: would not play.");
                    return;
                }

                if (file.exists()) {
                    TGLog.i(TAG, "[download]: file exist , start play");
                    synchronized (lock) {
                        if (!destroyCalled) {
                            TGLog.i(TAG, "[download]: playing ...");
                            playSound(file.getAbsolutePath());
                        } else {
                            TGLog.i(TAG, "[download]: can not play because destroyed");
                        }
                    }
                } else {
                    TGLog.i(TAG, "[download]: file NOT exist !");
                }
            } catch (Throwable e) {
                TGLog.i(TAG, "[download]: e = " + Log.getStackTraceString(e));
            }
        });
    }

    public void destroy() {
        if (!BuildConfig.device_addSupport_sound_play_enabled) {
            return;
        }
        synchronized (lock) {
            TGLog.i(TAG, "[destroy] ...");
            destroyCalled = true;
            releaseMediaPlayer();
        }
    }

    private void releaseMediaPlayer() {
        TGLog.d(TAG, "[releaseMediaPlayer] mediaPlayer = " + mediaPlayer);
        if (mediaPlayer != null) {
            try {
                if (mediaPlayer.isPlaying()) {
                    TGLog.d(TAG, "[releaseMediaPlayer] pause");
                    mediaPlayer.pause();
                }
                mediaPlayer.release();
                TGLog.d(TAG, "[releaseMediaPlayer] release");
            } catch (Throwable ex) {}
            mediaPlayer = null;
        }
    }

    private void playSound(String play) {
        final File file = new File(play);
        TGLog.d(TAG, "[playSound] file path =" + file.getAbsolutePath());
        if (!file.exists() || !file.isFile() || file.length() <= 0) {
            TGLog.i(TAG, "[playSound] file not exist");
            return;
        }

        try {
            resetMediaPlayer();
            mediaPlayer.setDataSource(play);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(mp -> {
                if (!destroyCalled) {
                    TGLog.d(TAG, "[playSound] prepared, start play");
                    mediaPlayer.start();
                } else {
                    TGLog.d(TAG, "[playSound] prepared, but destroyed, not play");
                }
            });
            mediaPlayer.setOnCompletionListener(player -> {
                TGLog.d(TAG, "[playSound] complete.");
                releaseMediaPlayer();
            });
        } catch (Throwable e) {
            TGLog.d(TAG, "[playSound] error =" + Log.getStackTraceString(e));
        }
    }

    private void resetMediaPlayer(){
        if (mediaPlayer == null){
            mediaPlayer = new MediaPlayer();
        }
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.reset();
        }
    }

}
